package bursy.finance.model.generator;

import bursy.finance.common.StringUtils;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class ModelGenerator {
    
    private static final String RES_FOLDER = "res";

    private static final String TABLE_NODE_NAME = "table";
    private static final String FIELD_NODE_NAME = "field";

    private static final String NAME_PARAMETER = "name";
    private static final String TYPE_PARAMETER = "type";
    private static DocumentBuilder dBuilder;
    
    public static void generateModels() throws ModelGeneratorException {
        if (dBuilder == null) {
            initDocumentBuilder();
        }
        
        File resFolder = new File(RES_FOLDER);
        for (File xmlFile : resFolder.listFiles()) {
            processFile(xmlFile);
        }
    }
    
    private static void initDocumentBuilder() throws ModelGeneratorException {
        DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
        try {
            dBuilder = dbFactory.newDocumentBuilder();
        } catch (ParserConfigurationException e) {
            throw new ModelGeneratorException("Unable to initialize the document builder"
                    + "for xml parsing. Closing generator.", e);
        }
    }
    
    private static void processFile(File xmlFile) throws ModelGeneratorException {
        ModelDataBean data = prepareModelData(xmlFile);
        writeModelData(data);
    }
    
    private static ModelDataBean prepareModelData(File xmlFile)
            throws ModelGeneratorException {
        String xmlName = null;
        ModelDataBean resultBean = new ModelDataBean();
        try {
            xmlName = xmlFile.getAbsolutePath();
            
            Document doc = dBuilder.parse(xmlFile);
            doc.getDocumentElement().normalize();
            
            Element root = doc.getDocumentElement();
            resultBean.setName(getTableName(root, xmlName));
            
            List<FieldDataBean> fieldDataBeans = new ArrayList();
            NodeList fields = root.getElementsByTagName(FIELD_NODE_NAME);

            int fieldsCount = fields.getLength();
            for (int i = 0; i < fieldsCount; i++) {
                fieldDataBeans.add(processField(fields.item(i), xmlName));
            }

            resultBean.setData(processFieldsData(fieldDataBeans));

        } catch (SAXException | IOException e) {
            throw new ModelGeneratorException("Unable to parse the xml: "
                    + xmlName, e);
        }
        return resultBean;
    }
    
    private static String getTableName(Element root, String xmlName)
            throws ModelGeneratorException {
        if (root == null) {
            throw new ModelGeneratorException(
                    "Root node is null for xml: " + xmlName);
        }

        if (!TABLE_NODE_NAME.equals(root.getNodeName())) {
            throw new ModelGeneratorException(
                    "Root node isn't " + TABLE_NODE_NAME + " for xml: " + xmlName);
        }
        
        String tableName = root.getAttribute(NAME_PARAMETER);
        
        if (StringUtils.isEmpty(tableName)) {
            throw new ModelGeneratorException("No table name in xml: " + xmlName);
        }

        return tableName;
    }
    
    private static FieldDataBean processField(Node field, String xmlName)
            throws ModelGeneratorException {
        if (field == null || field.getNodeType() != Node.ELEMENT_NODE) {
            throw new ModelGeneratorException("Incorrect field in xml: " + xmlName);
        }
        
        Element fieldElement = (Element) field;
        String name = fieldElement.getAttribute(NAME_PARAMETER);
        if (StringUtils.isEmpty(name)) {
            throw new ModelGeneratorException("Field with no name in xml: " + xmlName);
        }
        
        String type = fieldElement.getAttribute(TYPE_PARAMETER);
        if (StringUtils.isEmpty(type)) {
            throw new ModelGeneratorException("Field with name " + name
                    + " has no type in xml: " + xmlName);
        }
        
        FieldDataBean bean = new FieldDataBean();
        bean.setName(name);
        bean.setType(type);
        return bean;
    }
    
    private static StringBuilder processFieldsData(List<FieldDataBean> fieldsData) {
        StringBuilder data = new StringBuilder();
        // TODO: generate stringbuilder with java data here
        return data;
    }
    
    private static void writeModelData(ModelDataBean data) {
        // TODO: Write data from stringbuilder here
        /*try {
         PrintWriter writer = new PrintWriter("test.txt", "UTF-8");
         writer.println("The first line");
         writer.println("The second line");
         writer.close();
         } catch (Exception e) {
         System.out.println("lel");
         }*/
    }
}
